package com.quick.framework.filter;


import com.alibaba.fastjson2.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;
import org.springframework.http.MediaType;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;

import java.io.CharArrayWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.*;

/**
 * 请求过滤器
 *
 * @Author: Administrator
 * @Date: 2023/7/25
 */
@Slf4j
public class RequestLoggingFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        HttpServletResponse httpResponse = (HttpServletResponse) response;
        // 记录请求开始时间
        long startTime = System.currentTimeMillis();
        // 获取请求URL和方法
        String url = httpRequest.getRequestURL().toString();
        String method = httpRequest.getMethod();
        // 获取 POST 请求参数
        String requestParameters;
        if (isJsonRequest(httpRequest)) {
            requestParameters = getRequestBody(httpRequest);
        } else {
            requestParameters = JSONObject.toJSONString(getRequestParameters(httpRequest));
        }
        MDC.put("requestId", UUID.randomUUID().toString());
        log.info("Request url: {} ", url);
        log.info("Request method: {} ", method);
        log.info("Request data: {} ", requestParameters);
        // 执行请求
        chain.doFilter(request, response);
        // 计算响应耗时
        long endTime = System.currentTimeMillis();
        long duration = endTime - startTime;
        // 打印响应耗时
        log.info("Response data: {} ", getResponseBody(httpResponse));
        log.info("Response time: {} ms", duration);
        MDC.remove("requestId");
    }

    private Map<String, List<String>> getRequestParameters(HttpServletRequest request) {
        Map<String, List<String>> params = new HashMap<>(16);
        Enumeration<String> paramNames = request.getParameterNames();

        while (paramNames.hasMoreElements()) {
            String paramName = paramNames.nextElement();
            String[] paramValues = request.getParameterValues(paramName);
            params.put(paramName, Arrays.asList(paramValues));
        }

        return params;
    }

    private boolean isJsonRequest(HttpServletRequest request) {
        String contentType = request.getContentType();
        return contentType != null && contentType.contains(MediaType.APPLICATION_JSON_VALUE);
    }

    private String getRequestBody(HttpServletRequest request) throws IOException {
        StringBuilder body = new StringBuilder();
        Scanner scanner = new Scanner(request.getInputStream());
        while (scanner.hasNextLine()) {
            body.append(scanner.nextLine());
        }
        return body.toString();
    }

    private String getResponseBody(HttpServletResponse response) throws IOException {
        ResponseWrapper responseWrapper = new ResponseWrapper(response);
        String responseBody = responseWrapper.getContent();
        responseWrapper.flushBuffer();
        return responseBody;
    }


    public static class ResponseWrapper extends HttpServletResponseWrapper {
        private final CharArrayWriter writer;

        public ResponseWrapper(HttpServletResponse response) {
            super(response);
            writer = new CharArrayWriter();
        }

        @Override
        public PrintWriter getWriter() {
            return new PrintWriter(writer);
        }

        @Override
        public String toString() {
            return writer.toString();
        }

        public String getContent() {
            return toString();
        }
    }
}

